home *** CD-ROM | disk | FTP | other *** search
- /* Garbage collection */
-
- #include "params.h"
- #include "gambit.h"
- #include "struct.h"
- #include "os.h"
- #include "opcodes.h"
- #include "run.h"
-
-
- /*---------------------------------------------------------------------------*/
-
-
- void gc_flip();
- void gc_scan_range();
-
-
- long gc_report; /* index of '##gc-report' variable */
-
-
- #ifdef DEBUG_GC
- SCM_obj scanned_object;
- void show_state();
- #endif
-
-
- void gc()
- { char *nb, *nt; /* new space bottom and top */
- SCM_obj *fb, *ft; /* free space bottom and top */
- long cpu_times1[2], cpu_times2[2];
-
- os_cpu_times( cpu_times1 );
-
- os_notify_gc_begin( SCM_obj_to_int(pstate->id),
- (long)(sstate->globals[gc_report].value != (long)SCM_false) );
-
- if (pstate->heap_old > pstate->heap_bot)
- { pstate->heap_old = pstate->heap_bot;
- nb = pstate->heap_mid;
- nt = pstate->heap_top;
- }
- else
- { pstate->heap_old = pstate->heap_mid;
- nb = pstate->heap_bot;
- nt = pstate->heap_mid;
- }
-
- gc_flip( (char *)sstate, sstate->const_top, nb, nt, &fb, &ft );
-
- pstate->heap_lim = ((char *)fb) + pstate->heap_margin + (HEAP_ALLOCATION_FUDGE)*sizeof(SCM_obj);
- pstate->heap_ptr = (char *)ft;
-
- pstate->closure_lim = (char *)ft;
- pstate->closure_ptr = (char *)ft;
-
- os_notify_gc_end( SCM_obj_to_int(pstate->id), pstate->heap_mid, pstate->heap_bot, (char *)fb, (char *)ft,
- (long)(sstate->globals[gc_report].value != (long)SCM_false) );
-
- os_cpu_times( cpu_times2 );
-
- pstate->stats_counters[STAT_GC] += (cpu_times2[0] - cpu_times1[0]) +
- (cpu_times2[1] - cpu_times1[1]);
- }
-
-
- /*---------------------------------------------------------------------------*/
-
-
- #define gc_scan_closure(ptr,header) \
- gc_scan_range((SCM_obj *)ptr, SCM_closure_slots(header), (long)sizeof(SCM_obj))
-
-
- void gc_scan_roots()
- { long i, g, n, m;
- char *ptr, *limit;
-
- /* scan processor local storage (each processor has its own) */
-
- #ifdef DEBUG_GC
- scanned_object = 0;
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING processor local storage]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- gc_scan_range( (SCM_obj *)pstate->processor_storage,
- (long)(sizeof(pstate->processor_storage) / sizeof(SCM_obj)),
- (long)sizeof(SCM_obj) );
-
- /* scan global vars (distribute work among processors) */
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING global variables]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- g = SCM_obj_to_int( sstate->globals[GLOBAL_VAR_COUNT].value );
- n = SCM_obj_to_int(pstate->nb_processors);
- m = g/n;
- if (SCM_obj_to_int(pstate->id) < (g%n)) m++;
- gc_scan_range( (SCM_obj *)&sstate->globals[SCM_obj_to_int(pstate->id)].value, m, n*sizeof(struct global_rec) );
-
- for (i=0; i<m; i++)
- sstate->globals[SCM_obj_to_int(pstate->id)+i*n].jump_adr =
- (long)&sstate->tramps[SCM_obj_to_int(pstate->id)+i*n];
-
- /* scan stack (each processor has an independent stack) */
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING stack]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- gc_scan_range( (SCM_obj *)pstate->stack_ptr,
- (long)(pstate->ltq_head[-1] - pstate->stack_ptr),
- (long)sizeof(SCM_obj) );
-
- /* scan work queue (each processor has its own) */
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- os_warn( "[%d: SCANNING work queue]\n", SCM_obj_to_int(pstate->id) );
- #endif
-
- gc_scan_range( (SCM_obj *)&pstate->workq_head, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->workq_tail, 1L, (long)sizeof(SCM_obj) );
-
- /* scan current task (each processor has its own) */
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING current task]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- gc_scan_range( (SCM_obj *)&pstate->current_task, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->parent_ret, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->parent_frame, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->current_dyn_env, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->temp_task, 1L, (long)sizeof(SCM_obj) );
- gc_scan_range( (SCM_obj *)&pstate->response, 1L, (long)sizeof(SCM_obj) );
-
- /* scan constant space (each processor GCs its own copy) */
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING constant space (with headers)]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- ptr = sstate->const_bot;
- limit = sstate->const_bptr;
-
- while (ptr < limit)
- { long len, header = *(long *)ptr;
-
- ptr += sizeof(long);
-
- if (SCM_header_procedure(header))
- { len = SCM_procedure_length( header );
- #ifdef DEBUG_GC
- scanned_object = (long)ptr - sizeof(SCM_obj) + SCM_type_PROCEDURE;
- #endif
- if (SCM_header_closure(header))
- gc_scan_closure(ptr,header);
- else
- { long *p, nb_cst;
- p = (long *)(ptr + len);
- nb_cst = SCM_obj_to_int( *(--p) ) - 1;
- gc_scan_range( (SCM_obj *)(p-nb_cst), nb_cst, (long)sizeof(SCM_obj) );
- }
- }
- else
- { len = SCM_header_length( header );
- #ifdef DEBUG_GC
- scanned_object = (long)ptr - sizeof(SCM_obj) + SCM_type_SUBTYPED;
- #endif
- if (SCM_subtype_is_ovector(SCM_header_subtype( header )))
- gc_scan_range((SCM_obj *)ptr, SCM_header_slots(header), (long)sizeof(SCM_obj));
- }
-
- ptr = (char *)SCM_align(ptr+len);
- }
-
- #ifdef DEBUG_GC
- scanned_object = 0;
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING constant space (no headers)]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- gc_scan_range( (SCM_obj *)sstate->const_tptr,
- (long)((SCM_obj *)sstate->const_top - (SCM_obj *)sstate->const_tptr),
- (long)sizeof(SCM_obj));
- }
-
-
- /*===========================================================================*/
- /* Machine independent code follows */
- /*===========================================================================*/
-
-
- /*-----------------------------------------------------------------------------
- *
- * Garbage collector for Gambit
- *
- * Note: this garbage collector assumes that objects are represented
- * as specified in the document "gambit/doc/repr".
- *
- */
-
-
- /*
-
- Layout of memory during a GC:
-
- (note that the location of old space and new space reverses at every GC)
-
-
- HEAP
- Low addresses
- _________________________
- / | |
- / | |
- | | |
- | | |
- | | ACTIVE OBJECTS |
- | | |
- OLD SPACE | | + |
- | | |
- | | GARBAGE |
- | | |
- | | |
- \ | |
- \ |_________________________|
- / |. . . . . . . . . . . . .|
- / |. subtyped & procedures .|
- | |. . . & weak pairs . . .|
- | |. . (with headers) . . .| <---- bot_scan |
- | |. . . . . . . . . . . . .| |
- | |_ _ _ _ _ _ _ _ _ _ _ _ _| |
- | | | <---- bot_alloc \|/
- | | |
- NEW SPACE | | FREE MEM |
- | | |
- | |_ _ _ _ _ _ _ _ _ _ _ _ _|
- | |. . . . . . . . . . . . .| <---- top_alloc /|\
- | |. pairs & placeholders .| <---- top_scan |
- | |. . . (no headers) . . .| |
- \ |. . . . . . . . . . . . .| |
- \ |_________________________| |
-
- High addresses
-
- */
-
-
- long const_bot, const_top; /* Limits of constant space */
- SCM_obj *bot_alloc, *top_alloc; /* Allocation pointers */
- SCM_obj *weak_pairs; /* Chain of weak pairs */
-
-
- #ifdef DEBUG_GC
-
- void show_state()
- { os_warn( "[%d: ", SCM_obj_to_int(pstate->id) );
- os_warn( "bot_alloc=0x%x, ", (long)bot_alloc );
- os_warn( "top_alloc=0x%x]\n", (long)top_alloc );
- }
-
- void show_object( object, from )
- SCM_obj object, *from;
- { SCM_obj *adr = (object != 0) ? SCM_object_adr(object) : from-10;
- int i;
- for (i=0; i<20; i++)
- { os_warn( "0x%x = ", (long)(adr+i) );
- os_warn( "0x%x\n", adr[i] );
- }
- }
-
- void show_invalid( value, object, from )
- SCM_obj value, object, *from;
- { os_warn( "\nGC ERROR: object 0x%x ", (long)object );
- os_warn( "at 0x%x ", (long)from );
- os_warn( "contains invalid value 0x%x\n", (long)value );
- show_object( object, 0L );
- os_quit();
- }
-
- int correct_value( value )
- SCM_obj value;
- { if ((SCM_type(value)!=SCM_type_FIXNUM)&&(SCM_type(value)!=SCM_type_SPECIAL))
- if ((((long)value) < const_bot) || (((long)value) >= const_top))
- { int i;
- for (i=SCM_obj_to_int(pstate->nb_processors)-1; i>=0; i--)
- if ((value >= (long)pstate->ps[i]->heap_bot) &&
- (value <= (long)pstate->ps[i]->heap_top)) return 1;
- return 0;
- }
- return 1;
- }
-
- #define CHECK_VALID(value,object,from) { if (!correct_value( value )) show_invalid( value, object, from ); }
-
- #else
-
- #define CHECK_VALID(value,object,from)
-
- #endif
-
-
- /*-----------------------------------------------------------------------------
- *
- * Scan a range of memory for garbage-collectable objects. Referenced
- * objects are copied from OLD space to NEW space.
- *
- */
-
-
- #define FORWARD_NO_HEADER FORWARD(SCM_copied_no_header(slot0),adr[1])
- #define FORWARD_HEADER FORWARD(SCM_copied_header(slot0),slot0)
- #define FORWARD_CLOSURE FORWARD(!SCM_header_closure(slot0),slot0)
- #define FORWARD(copied,forw_ptr) \
- adr = SCM_object_adr(object); /* Get address of object */ \
- read_and_lock(adr, slot0); /* Lock it and get slot 0 */ \
- if (copied) /* Has it been copied? */ \
- { *from = forw_ptr; /* Update reference */ \
- CHECK_VALID( forw_ptr, scanned_object, from ); \
- unlock(adr, slot0); /* and unlock object */ \
- } \
- else
-
-
- void gc_scan_range( from, count, step )
- SCM_obj *from; /* Where to start scanning */
- long count; /* Number of objects to scan */
- long step; /* Step between objects (in bytes) */
- { register SCM_obj object; /* Object being checked */
- register SCM_obj object_copy; /* Object after data copied */
- register SCM_obj *adr; /* Pointer to data if mem alloc obj */
- register long slot0; /* First slot of that data */
- register SCM_obj len; /* Length of headed object */
- register SCM_obj *b_alloc = bot_alloc; /* Local copy of bot_alloc */
- register SCM_obj *t_alloc = top_alloc; /* Local copy of top_alloc */
-
- while (count-- > 0) /* Scan every object */
- { object = *from; /* Fetch next object */
- Rescan:
- if ((((long)object) < const_bot) || /* Don't process objects */
- (((long)object) >= const_top)) /* stored in constant space */
- {
- #ifdef DEBUG_GC
- if (!correct_value( object ))
- { os_warn( "\nGC ERROR: found invalid value 0x%x ", (long)object );
- os_warn( "at 0x%x while scanning\n", (long)from );
- show_object( 0L, from );
- os_quit();
- }
- #endif
- switch SCM_type(object) /* Dispatch on type */
- { case SCM_type_PAIR:
- FORWARD_NO_HEADER
- { CHECK_VALID( adr[1], object, from );
- CHECK_VALID( slot0, object, from );
- *(--t_alloc) = adr[1]; /* Allocate and copy pair */
- *(--t_alloc) = slot0;
- object_copy = SCM_add_type(t_alloc, SCM_type_PAIR);
- adr[1] = object_copy; /* Remember where copied */
- store_and_unlock(adr, (long)SCM_BH); /* Mark as copied & unlock */
- *from = object_copy; /* Update reference */
- CHECK_VALID( object_copy, scanned_object, from );
- }
- break;
-
- case SCM_type_PROCEDURE: /* Must be closure */
- FORWARD_CLOSURE
- { object_copy = SCM_add_type(b_alloc, SCM_type_PROCEDURE);
- *(b_alloc++) = slot0;
- store_and_unlock(adr, object_copy); /* remember where copied */
- len = SCM_procedure_length(slot0);
- adr++;
- while (len>0)
- { CHECK_VALID( *adr, object, from );
- *(b_alloc++) = *(adr++);
- len -= sizeof(SCM_obj);
- }
- b_alloc = (SCM_obj *)SCM_align(b_alloc);
- *from = object_copy; /* update reference */
- CHECK_VALID( object_copy, scanned_object, from );
- }
- break;
-
- case SCM_type_SUBTYPED:
- FORWARD_HEADER
- { object_copy = SCM_add_type(b_alloc, SCM_type_SUBTYPED);
- *(b_alloc++) = slot0;
- store_and_unlock(adr, object_copy); /* remember where copied */
- len = SCM_header_length(slot0);
- adr++;
- #ifdef DEBUG_GC
- if (SCM_subtype_is_ovector(SCM_header_subtype( slot0 )))
- while (len>0)
- { CHECK_VALID( *adr, object, from );
- *(b_alloc++) = *(adr++);
- len -= sizeof(SCM_obj);
- }
- else
- #endif
- while (len>0)
- { *(b_alloc++) = *(adr++); len -= sizeof(SCM_obj); }
- b_alloc = (SCM_obj *)SCM_align(b_alloc);
- *from = object_copy; /* update reference */
- CHECK_VALID( object_copy, scanned_object, from );
- }
- break;
-
- case SCM_type_PLACEHOLDER:
- /* Assumption: slot 0 is the value slot, and is itself
- if not yet determined */
- FORWARD_NO_HEADER
- { if (slot0 != object) /* Determined? */
- { unlock(adr, slot0); /* Unlock & restore value */
- object = slot0; /* Rescan value */
- *from = object; /* Replace P.H. by value */
- CHECK_VALID( object, scanned_object, from );
- goto Rescan;
- }
- CHECK_VALID( adr[3], object, from );
- CHECK_VALID( adr[2], object, from );
- CHECK_VALID( adr[1], object, from );
- CHECK_VALID( slot0, object, from );
- *(--t_alloc) = adr[3];
- *(--t_alloc) = adr[2];
- *(--t_alloc) = adr[1];
- *(--t_alloc) = slot0;
- object_copy = SCM_add_type(t_alloc, SCM_type_PLACEHOLDER);
- adr[1] = object_copy; /* Remember where copied */
- store_and_unlock(adr, (long)SCM_BH); /* Mark as copied & unlock */
- *from = object_copy; /* Update reference */
- CHECK_VALID( object_copy, scanned_object, from );
- }
- break;
-
- case SCM_type_WEAK_PAIR:
- FORWARD_NO_HEADER
- { CHECK_VALID( adr[1], object, from );
- CHECK_VALID( slot0, object, from );
- *(b_alloc++) = SCM_make_header(3*sizeof(SCM_obj),SCM_subtype_WEAK_PAIR);
- *(b_alloc++) = (SCM_obj)weak_pairs;
- weak_pairs = b_alloc;
- object_copy = SCM_add_type(b_alloc, SCM_type_WEAK_PAIR);
- *(b_alloc++) = slot0; /* Allocate and copy pair */
- *(b_alloc++) = adr[1];
- adr[1] = object_copy; /* Remember where copied */
- store_and_unlock(adr, (long)SCM_BH); /* Mark as copied & unlock */
- *from = object_copy; /* Update reference */
- CHECK_VALID( object_copy, scanned_object, from );
- }
- break;
-
- case SCM_type_FIXNUM:
- case SCM_type_SPECIAL: break;
-
- default:
- os_warn( "\nGC ERROR: Bad type code, object=0x%x", (long)object );
- #ifdef DEBUG_GC
- if (scanned_object != 0) os_warn( " in 0x%x", scanned_object );
- #endif
- os_warn( " at 0x%x\n", (long)from );
- #ifdef DEBUG_GC
- show_object( scanned_object, from );
- #endif
- os_quit();
- }
- }
- from = (SCM_obj *)(((char *)from) + step); /* Move to next object */
- }
-
- bot_alloc = b_alloc; /* Put copies back */
- top_alloc = t_alloc;
- }
-
-
- /*-----------------------------------------------------------------------------
- *
- * Main procedure of the garbage collector.
- *
- */
-
- void gc_flip( const_b, const_t, new_b, new_t, free_b, free_t )
- char *const_b, *const_t; /* Location of constant space */
- char *new_b, *new_t; /* Location of new space */
- SCM_obj **free_b, **free_t; /* Location of free space after GC */
- { SCM_obj *top_scan, *bot_scan; /* Pointers to scan copied data */
-
- const_bot = (long)const_b;
- const_top = (long)const_t;
-
- bot_alloc = (SCM_obj *)new_b;
- top_alloc = (SCM_obj *)new_t;
-
- bot_scan = bot_alloc;
- top_scan = top_alloc;
-
- weak_pairs = NULL;
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { os_warn( "[%d: ", SCM_obj_to_int(pstate->id) );
- os_warn( "constant space = 0x%x..", (long)sstate->const_bot );
- os_warn( "0x%x ", (long)sstate->const_bptr );
- os_warn( "0x%x..", (long)sstate->const_tptr );
- os_warn( "0x%x]\n", (long)sstate->const_top );
- }
- #endif
-
- gc_scan_roots(); /* Call gc_scan_range on each root */
-
- /* Scan both allocation areas and copy the objects referenced */
-
- Scan:
-
- #ifdef DEBUG_GC
- scanned_object = 0;
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING heap (no headers)]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- { long count = top_scan - top_alloc; /* Scan objects without headers */
- gc_scan_range(top_alloc, count, (long)sizeof(SCM_obj));
- top_scan -= count;
- }
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- { show_state();
- os_warn( "[%d: SCANNING heap (with headers)]\n", SCM_obj_to_int(pstate->id) );
- }
- #endif
-
- while (bot_scan != bot_alloc) /* Scan objects with headers */
- { long len, header = (long) *(bot_scan++);
-
- if (SCM_header_procedure(header))
- { len = SCM_procedure_length( header );
- #ifdef DEBUG_GC
- scanned_object = (long)bot_scan - sizeof(SCM_obj) + SCM_type_PROCEDURE;
- #endif
- if (SCM_header_closure(header))
- gc_scan_closure(bot_scan,header);
- }
- else
- { len = SCM_header_length( header );
- #ifdef DEBUG_GC
- scanned_object = (long)bot_scan - sizeof(SCM_obj) + SCM_type_SUBTYPED;
- #endif
- if (SCM_subtype_is_ovector(SCM_header_subtype( header )))
- gc_scan_range(bot_scan, SCM_header_slots(header), (long)sizeof(SCM_obj));
- else if (SCM_header_subtype( header ) == SCM_subtype_WEAK_PAIR)
- gc_scan_range(bot_scan+1, 1L, (long)sizeof(SCM_obj)); /* scan CDR only */
- }
-
- bot_scan = (SCM_obj *)SCM_align(((char *)bot_scan) + len);
- }
-
- if (top_scan != top_alloc) goto Scan; /* Scan newly copied objects */
-
- *free_b = bot_alloc;
- *free_t = top_alloc;
-
- barrier( "GC1" );
-
- /* Update all weak pairs */
-
- while (weak_pairs != NULL)
- { SCM_obj car = weak_pairs[1];
- SCM_obj *adr;
- if ((car < const_bot) || (car >= const_top))
- switch SCM_type(car)
- { case SCM_type_PAIR:
- case SCM_type_WEAK_PAIR:
- case SCM_type_PLACEHOLDER:
- adr = SCM_object_adr(car);
- car = adr[0];
- if (SCM_copied_no_header(car)) car = adr[1]; else car = SCM_false;
- break;
- case SCM_type_PROCEDURE:
- adr = SCM_object_adr(car);
- car = adr[0];
- if (SCM_header_closure(car)) car = SCM_false;
- break;
- case SCM_type_SUBTYPED:
- adr = SCM_object_adr(car);
- car = adr[0];
- if (!SCM_copied_header(car)) car = SCM_false;
- break;
- case SCM_type_FIXNUM:
- case SCM_type_SPECIAL:
- break;
- default:
- os_warn( "\nGC ERROR: Bad type code for CAR of WEAK_PAIR, CAR=0x%x", (long)car );
- os_warn( " at 0x%x\n", (long)weak_pairs );
- os_quit();
- }
- weak_pairs[1] = car;
- weak_pairs = (SCM_obj *)weak_pairs[-1];
- }
-
- #ifdef DEBUG_GC
- if (sstate->debug)
- show_state();
- #endif
-
- barrier( "GC2" );
- }
-
-
- /*---------------------------------------------------------------------------*/
-